﻿using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;


namespace Having.Site.Encrypt
{
    public class Cryptography
    {

        /// <summary>
        /// 转换为Base64字符代码
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string Base64(string str)
        {
            byte[] bytes = Encoding.UTF8.GetBytes(str);
            return Convert.ToBase64String(bytes);
        }

        /// <summary>
        /// 使用md5加密密码(32位)[使用指定编码]
        /// </summary>
        /// <param name="str">要加密的密码串</param>
        /// <param name="code">指定编码</param>
        /// <returns></returns>
        public static string MD5(string str, Encoding code)
        {
            StringBuilder sb = new StringBuilder(32);

            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] t = md5.ComputeHash(code.GetBytes(str));
            for (int i = 0; i < t.Length; i++)
            {
                sb.Append(t[i].ToString("x").PadLeft(2, '0'));
            }
            md5.Clear();
            return sb.ToString();
        }

        public static string MD5(string str, string code="utf-8")
        {
            return MD5(str, Encoding.GetEncoding(code));
        }
        /// <summary>
        /// 16位MD5加密（使用指定编码)
        /// </summary>
        /// <param name="str">要加密的密码串</param>
        /// <param name="code">指定编码</param>
        /// <returns></returns>
        public static string MD5_16(string str, Encoding code)
        {
            return MD5(str, code).Substring(8, 16);
        }

        public static string MD5_16(string str, string code="utf-8")
        {
            return MD5_16(str, Encoding.GetEncoding(code));
        }

        /// <summary>
        /// 使用sha1加密(40位)
        /// </summary>
        /// <param name="str">要加密的密码串</param>
        /// <param name="code">指定编码</param>
        /// <returns></returns>
        public static string SHA1(string str, Encoding code)
        {
            //建立SHA1对象
            SHA1 sha = new SHA1CryptoServiceProvider();
            byte[] dataToHash = code.GetBytes(str);
            //Hash运算
            byte[] dataHashed = sha.ComputeHash(dataToHash);
            //将运算结果转换成string
            string hash = BitConverter.ToString(dataHashed).Replace("-", "");
            return hash;
        }
        /// <summary>
        /// 使用sha1加密(40位)(使用默认的utf8)
        /// </summary>
        /// <param name="str">要加密的密码串</param>
        /// <param name="code">指定编码</param>
        /// <returns></returns>
        public static string SHA1(string str, string code="utf-8")
        {
            return SHA1(str, Encoding.GetEncoding(code));
        }
        /// <summary>
        /// 使用sha256加密
        /// </summary>
        /// <param name="str">要加密的字符</param>
        /// <param name="code"></param>
        /// <returns></returns>
        public static string SHA256(string str, Encoding code)
        {
            System.Security.Cryptography.SHA256 sha = new SHA256Managed();
            byte[] dataToHash = code.GetBytes(str);
            byte[] dataHashed = sha.ComputeHash(dataToHash);
            //将运算结果转换成string
            string hash = BitConverter.ToString(dataHashed).Replace("-", "");
            return hash;
        }
        /// <summary>
        /// 使用sha256加密
        /// </summary>
        /// <param name="str">要加密的字符</param>
        /// <param name="code"></param>
        /// <returns></returns>
        public static string SHA256(string str, string code="utf-8")
        {
            return SHA256(str, Encoding.GetEncoding(code));
        }
        /// <summary>
        /// 使用SHA512加密
        /// </summary>
        /// <param name="str">要加密的字符</param>
        /// <param name="code"></param>
        /// <returns></returns>
        public static string SHA512(string str, Encoding code)
        {
            SHA512 sha = new SHA512Managed();
            byte[] dataToHash = code.GetBytes(str);
            byte[] dataHashed = sha.ComputeHash(dataToHash);
            string hash = BitConverter.ToString(dataHashed).Replace("-", "");
            return hash;
        }
        /// <summary>
        /// 使用SHA512加密
        /// </summary>
        /// <param name="str">要加密的字符</param>
        /// <param name="code"></param>
        /// <returns></returns>
        public static string SHA512(string str, string code = "utf-8")
        {
            return SHA512(str, Encoding.GetEncoding(code));
        }
        /// <summary>
        /// 使用SHA3-224方式加密
        /// </summary>
        /// <param name="str">加密的数据</param>
        /// <param name="code">编码</param>
        /// <returns></returns>
        public static string SHA3With224(string str, Encoding code)
        {
            var sha = Sha3.Sha3.Sha3With224();
            byte[] dataToHash = code.GetBytes(str);
            byte[] dataHashed = sha.ComputeHash(dataToHash);
            string hash = BitConverter.ToString(dataHashed).Replace("-", "");
            return hash;
        }

        /// <summary>
        /// 使用SHA3-224方式加密
        /// </summary>
        /// <param name="str">加密的数据</param>
        /// <param name="code">编码</param>
        /// <returns></returns>
        public static string SHA3With224(string str, string code = "utf-8")
        {
            return SHA3With224(str, Encoding.GetEncoding(code));
        }

        /// <summary>
        /// 使用SHA3-256方式加密
        /// </summary>
        /// <param name="str">加密的数据</param>
        /// <param name="code">编码</param>
        /// <returns></returns>
        public static string SHA3With256(string str, Encoding code)
        {
            var sha = Sha3.Sha3.Sha3With256();
            byte[] dataToHash = code.GetBytes(str);
            byte[] dataHashed = sha.ComputeHash(dataToHash);
            string hash = BitConverter.ToString(dataHashed).Replace("-", "");
            return hash;
        }

        /// <summary>
        /// 使用SHA3-256方式加密
        /// </summary>
        /// <param name="str">加密的数据</param>
        /// <param name="code">编码</param>
        /// <returns></returns>
        public static string SHA3With256(string str, string code = "utf-8")
        {
            return SHA3With256(str, Encoding.GetEncoding(code));
        }
        /// <summary>
        /// 使用SHA3-512方式加密
        /// </summary>
        /// <param name="str">加密的数据</param>
        /// <param name="code">编码</param>
        /// <returns></returns>
        public static string SHA3With512(string str, Encoding code)
        {
            var sha = Sha3.Sha3.Sha3With512();
            byte[] dataToHash = code.GetBytes(str);
            byte[] dataHashed = sha.ComputeHash(dataToHash);
            string hash = BitConverter.ToString(dataHashed).Replace("-", "");
            return hash;
        }

        /// <summary>
        /// 使用SHA3-512方式加密
        /// </summary>
        /// <param name="str">加密的数据</param>
        /// <param name="code">编码</param>
        /// <returns></returns>
        public static string SHA3With512(string str, string code = "utf-8")
        {
            return SHA3With512(str, Encoding.GetEncoding(code));
        }

        /// <summary>
        /// 有密码的AES加密
        /// </summary>
        /// <param name="toEncrypt">要加密的内容</param>
        /// <param name="key">密钥</param>
        /// <param name="aesoffer">配置aes的相关属性</param>
        /// <returns></returns>
        public static string AESEncrypt(string toEncrypt, byte[] key, Exend.AESOffer aesoffer=null)
        {
            byte[] resultArray = null;
            byte[] toEncryptArray = Encoding.UTF8.GetBytes(toEncrypt);
            using (RijndaelManaged rDel = new RijndaelManaged())
            {
                rDel.Key = key;
                if (aesoffer == null)
                {
                    aesoffer = new Exend.AESOffer();
                }
                rDel.Padding = aesoffer.PaddingMode;
                rDel.Mode = aesoffer.Mode;
                try
                {
                    if (rDel.Mode != CipherMode.ECB)
                    {
                        rDel.IV = aesoffer.IV;
                    }
                    ICryptoTransform cTransform = rDel.CreateEncryptor();
                    resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
                }
                catch
                { }
            }
            if (resultArray != null)
            {
                return Convert.ToBase64String(resultArray, 0, resultArray.Length);
            }
            else
            {
                return "";
            }
            
        }
        /// <summary>
        /// 有密码的AES解密
        /// </summary>
        /// <param name="toDecrypt">要加密的内容</param>
        /// <param name="key">密钥</param>
        /// <param name="IV">偏移量</param>
        /// <returns></returns>
        public static string AESDecrypt(string toDecrypt, byte[] key, Exend.AESOffer aesoffer = null)
        {
            byte[] resultArray = null;
            byte[] toEncryptArray = Convert.FromBase64String(toDecrypt);
            using (RijndaelManaged rDel = new RijndaelManaged())
            {
                rDel.Key = key;
                if (aesoffer == null)
                {
                    aesoffer = new Exend.AESOffer();
                }
                rDel.Padding = aesoffer.PaddingMode;
                rDel.Mode = aesoffer.Mode;
                //rDel.KeySize = aesoffer.Len;
                try
                {
                    if (rDel.Mode != CipherMode.ECB)
                    {
                        rDel.IV = aesoffer.IV;
                    }
                    ICryptoTransform cTransform = rDel.CreateDecryptor();
                    resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
                }
                catch(Exception e) 
                { 
                }
            }
            if (resultArray != null)
            {
                return UTF8Encoding.UTF8.GetString(resultArray);
            }
            else
            {
                return "";
            }
        }



        /// <summary>
        /// 有密码的AES加密(使用cbc模式)
        /// </summary>
        /// <param name="toEncrypt">要加密的内容</param>
        /// <param name="key">密钥</param>
        /// <param name="IV">偏移量</param>
        /// <returns></returns>
        public static string AESEncrypt(string toEncrypt, byte[] key, byte[] IV)
        {
            return AESEncrypt(toEncrypt, key, new Exend.AESOffer(PaddingMode.PKCS7, CipherMode.CBC, IV));
        }
        /// <summary>
        /// AES解密(使用cbc模式)
        /// </summary>
        /// <param name="toDecrypt">要加密的base64字符</param>
        /// <param name="key">密钥</param>
        /// <param name="IV">偏移量</param>
        /// <returns></returns>
        public static string AESDecrypt(string toDecrypt, byte[] key, byte[] IV)
        {
            return AESDecrypt(toDecrypt, key, new Exend.AESOffer(PaddingMode.PKCS7, CipherMode.CBC, IV));
        }

        /// <summary>
        /// 有密码的AES加密(使用cbc模式)
        /// </summary>
        /// <param name="toEncrypt">要加密的内容</param>
        /// <param name="key">密钥（字符），长度必须是16，24,32</param>
        /// <param name="IV">偏移量（字符）长度必须是16</param>
        /// <returns></returns>
        public static string AESEncrypt(string toEncrypt, string key, string IV)
        {
            var keybit = System.Text.Encoding.UTF8.GetBytes(key);
            var ivbit = System.Text.Encoding.UTF8.GetBytes(IV);
            return AESEncrypt(toEncrypt, keybit, ivbit);
        }
        /// <summary>
        /// AES解密(使用cbc模式)
        /// </summary>
        /// <param name="toDecrypt">要加密的base64字符</param>
        /// <param name="key">密钥（字符），长度必须是16，24,32</param>
        /// <param name="IV">偏移量（字符）长度必须是16</param>
        /// <returns></returns>
        public static string AESDecrypt(string toDecrypt, string key, string IV)
        {
            var keybit = System.Text.Encoding.UTF8.GetBytes(key);
            var ivbit = System.Text.Encoding.UTF8.GetBytes(IV);
            return AESDecrypt(toDecrypt, keybit, ivbit);
        }



        /// <summary>
        /// des加密(cbc模式，返回base64)
        /// </summary>
        /// <param name="toEecrypt">要加密的字符</param>
        /// <param name="key">必须是8位置，不足0补充</param>
        /// <param name="IV">必须是8位置，不足0补充</param>
        /// <returns></returns>
        public static string DESEncrypt(string toEecrypt, string key, string IV)
        {

            key = key.Length > 8 ? key.Substring(0, 8) : key;
            key = key.Length < 8 ? (key + "00000000").Substring(0, 8) : key;
            IV = IV.Length > 8 ? IV.Substring(0, 8) : IV;
            IV = IV.Length < 8 ? (IV + "00000000").Substring(0, 8) : IV;

            var eKey = Encoding.ASCII.GetBytes(key);
            var eIV = Encoding.ASCII.GetBytes(IV);
            return DESEncrypt(toEecrypt, eKey, eIV);
        }
        /// <summary>
        /// des解密（cbc模式）
        /// </summary>
        /// <param name="toDecrypt">要解密的base64长度</param>
        /// <param name="key">必须是8位置，不足0补充</param>
        /// <param name="IV">必须是8位置，不足0补充</param>
        /// <returns></returns>
        public static string DESDecrypt(string toDecrypt, string key, string IV)
        {
            key = key.Length > 8 ? key.Substring(0, 8) : key;
            key = key.Length < 8 ? (key + "00000000").Substring(0, 8) : key;
            IV = IV.Length > 8 ? IV.Substring(0, 8) : IV;
            IV = IV.Length < 8 ? (IV + "00000000").Substring(0, 8) : IV;

            var eKey = Encoding.ASCII.GetBytes(key);
            var eIV = Encoding.ASCII.GetBytes(IV);
            return DESDecrypt(toDecrypt, eKey, eIV);
        }

        /// <summary>
        /// des加密
        /// </summary>
        /// <param name="toEecrypt"></param>
        /// <param name="key"></param>
        /// <param name="IV"></param>
        /// <returns></returns>
        public static string DESEncrypt(string toEecrypt, byte[] key, byte[] IV)
        {
            try
            {
                DESCryptoServiceProvider des = new DESCryptoServiceProvider();

                byte[] inputByteArray = Encoding.UTF8.GetBytes(toEecrypt);

                des.Key = key;
                des.IV = IV;
                MemoryStream ms = new MemoryStream();
                using (CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write))
                {

                    cs.Write(inputByteArray, 0, inputByteArray.Length);
                    cs.FlushFinalBlock();
                }
                var ret= Convert.ToBase64String(ms.ToArray()); 
                ms.Dispose();
                des.Clear();
                return ret;
            }
            catch
            {
                return "";
            }
        }
        /// <summary>
        /// des解密
        /// </summary>
        /// <param name="toDecrypt"></param>
        /// <param name="key"></param>
        /// <param name="IV"></param>
        /// <returns></returns>
        public static string DESDecrypt(string toDecrypt, byte[] key, byte[] IV)
        {
            try
            {
                DESCryptoServiceProvider des = new DESCryptoServiceProvider();

                byte[] inputByteArray = Convert.FromBase64String(toDecrypt);

                //建立加密对象的密钥和偏移量，此值重要，不能修改
                des.Key = key;
                des.IV = IV;
                MemoryStream ms = new MemoryStream();
                using (CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(key, IV), CryptoStreamMode.Write))
                {
                    cs.Write(inputByteArray, 0, inputByteArray.Length);
                    cs.FlushFinalBlock();
                }
                des.Clear();
                return System.Text.Encoding.UTF8.GetString(ms.ToArray());
            }
            catch
            {
                return "";
            }
        }




        /// <summary>
        /// RSA
        /// </summary>
        /// <param name="toEncrypt">要加密的字符</param>
        /// <param name="public_key">公钥证书</param>
        /// <param name="isfile">公钥证书是文件还是字符串,是文件路径则是true</param>
        /// <param name="encodType"></param>
        /// <param name="signType">OAEP(默认)/Pkcs1</param>
        /// <returns></returns>
        public static string RSAEncrypt(string toEncrypt, string public_key,  bool isfile = false,string encodType = "utf-8",string signType= "OAEP")
        {
            var pstr = "";
            if (isfile)
            {
                pstr = System.IO.File.ReadAllText(public_key);
            }
            else
            {
                pstr = public_key;
            }
            IAsymmetricBlockCipher encryptEngine =null;
            switch (signType)
            {
                case "OAEP":
                    encryptEngine = new OaepEncoding(new RsaEngine());
                    break;
                case "Pkcs1":
                    encryptEngine = new Pkcs1Encoding(new RsaEngine());
                    break;
            }
            using (var txtreader = new StringReader(pstr))
            {
                var keyParameter = (AsymmetricKeyParameter)new PemReader(txtreader).ReadObject();
                encryptEngine.Init(true, keyParameter);
            }
            var bytesToEncrypt = Encoding.GetEncoding(encodType).GetBytes(toEncrypt);
            var encrypted = Convert.ToBase64String(encryptEngine.ProcessBlock(bytesToEncrypt, 0, bytesToEncrypt.Length));
            return encrypted;
        }
        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="toDecrypt">要解密的字符</param>
        /// <param name="private_key">私钥</param>
        /// <param name="isfile">私钥是文件还是字符串,是文件路径则是true</param>
        /// <param name="encodType"></param>
        /// <param name="signType">OAEP(默认)/Pkcs1,SHA1</param>
        /// <returns></returns>
        public static string RSADecrypt(string toDecrypt, string private_key, bool isfile = false, string encodType = "utf-8", string signType = "OAEP")
        {
            var pstr = "";
            if (isfile)
            {
                pstr = System.IO.File.ReadAllText(private_key);
            }
            else
            {
                pstr = private_key;
            }
            IAsymmetricBlockCipher decryptEngine = null;
            switch (signType)
            {
                case "OAEP":
                    decryptEngine = new OaepEncoding(new RsaEngine());
                    break;
                case "Pkcs1":
                    decryptEngine = new Pkcs1Encoding(new RsaEngine());
                    break;
            }
            using (var txtreader = new StringReader(pstr))
            {
                var keyPair = (AsymmetricCipherKeyPair)new PemReader(txtreader).ReadObject();
                decryptEngine.Init(false, keyPair.Private);
            }
            var bytesToDecrypt = Encoding.GetEncoding(encodType).GetBytes(toDecrypt);
            var decrypted = Encoding.UTF8.GetString(decryptEngine.ProcessBlock(bytesToDecrypt, 0, bytesToDecrypt.Length));
            return decrypted;
        }
    }
}
